之前座標的文章中,明白投影矩陣的作用是把觀察空間坐標轉化為標準化設備坐標。
我們要 2D 的 renderer,所以用正射投影矩阵(Orthographic Projection Matrix)
就可以了
glm::mat4 projection = glm::ortho(0.0f, width_, height_, 0.f, -1.0f, 1.0f);
我們要渲染東西,Shader 當然不可少囉。
VertexShader
#version 330 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec2 a_TexCoord;
out vec2 v_TexCoord;
uniform mat4 transform;
uniform mat4 projection;
void main()
{
gl_Position = projection * transform * vec4(a_Position, 1.0);
v_TexCoord = a_TexCoord;
}
fragmentShader
#version 330 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
uniform sampler2D u_Texture;
uniform vec4 ourColor;
void main()
{
color = ourColor * texture(u_Texture, v_TexCoord);
}
為了讓渲染更有條理,我們定義一個SpriteRenderer
的 class。
class SpriteRender {
public:
SpriteRender() = default;
SpriteRender(const std::shared_ptr<Shader>& shader);
~SpriteRender();
void Draw(std::shared_ptr<Texture2D>& texture, glm::vec2 pos, glm::vec2 size, float rotate = 0.0f, glm::vec4 color = glm::vec4(1.0f));
private:
std::shared_ptr<Shader> shader_;
std::shared_ptr<VertexArray> vertexArray_;
void Init();
};
void SpriteRender::Init() {
float vertices[5 * 4] = {
// ---- 位置 ----
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
uint32_t indices[2 * 3] = {
0, 1, 3,
1, 2, 3
};
vertexArray_ = std::make_shared<VertexArray>();
std::shared_ptr<VertexBuffer> vertexBuffer;
vertexBuffer = std::make_shared<VertexBuffer>(vertices, sizeof(vertices));
BufferLayout layout = {
{ShaderDataType::Float3, "a_Position"},
{ShaderDataType::Float2, "a_TexCoord"}};
vertexBuffer->setLayout(layout);
vertexArray_->addVertexBuffer(vertexBuffer);
std::shared_ptr<IndexBuffer> indexBuffer;
indexBuffer = std::make_shared<IndexBuffer>(indices, sizeof(indices) / sizeof(uint32_t));
vertexArray_->setIndexBuffer(indexBuffer);
vertexArray_->unbind();
}
void SpriteRender::Draw(std::shared_ptr<Texture2D>& texture, glm::vec2 pos, glm::vec2 size, float rotate, glm::vec4 color) {
texture->bind();
shader_->bind();
shader_->setFloat4("ourColor", color);
glm::mat4 transform(1.0f);
transform = glm::translate(transform, glm::vec3(pos, 0.0));
transform = glm::translate(transform, glm::vec3(0.5f*size.x, 0.5*size.y, 0.0f));
transform = glm::rotate(transform, rotate, glm::vec3(0.0f, 0.0f, 1.0f));
transform = glm::translate(transform, glm::vec3(-0.5f*size.x, -0.5f*size.y, 0.0f));
// transform = glm::translate(transform, glm::vec3(0.f, 0.f, 0.0f));
transform = glm::scale(transform, glm::vec3(size, 1.f));
shader_->setMat4("transform", transform);
vertexArray_->bind();
glDrawElements(GL_TRIANGLES, vertexArray_->getIndexBuffer()->getCount(), GL_UNSIGNED_INT, nullptr);
vertexArray_->unbind();
shader_->unbind();
texture->unbind();
}
接著,回到我們老久之前寫的Game
我們要開始渲染了
ResourceManager::loadShader("vShader.glsl", "fShader.glsl", "sprite");
renderer_ = std::make_shared<SpriteRender>(ResourceManager::getShader("sprite"));
glm::mat4 projection = glm::ortho(0.0f, width_, height_, 0.f, -1.0f, 1.0f);
auto& shader = ResourceManager::getShader("sprite");
shader->bind();
shader->setInt("u_Texture", 0);
shader->setMat4("projection", projection);
texture_ = ResourceManager::loadTexture("1.png", "gardevoir");
接著在Game::Render()
就可以 Render 了
void Game::Render() {
renderer_->Draw(texture_, glm::vec2(200.f, 200.f), glm::vec2(100.f, 100.f), -55.f, glm::vec4{1.0f, 1.0f, 1.0f, 1.0f});
}